#include <vector>
#include <queue>
#include "thread.hpp"
template <class T>
class pthreadPool
{
private:
    void pop(T &date)
    {
        date = _tasks.front();
        _tasks.pop();
    }

    static void *handlerTask(void *arg)
    {
        pthreadPool *th = static_cast<pthreadPool *>(arg);
        while (1)
        {
            pthread_mutex_lock(&(th->_mutex));
            while (th->_tasks.empty())
                pthread_cond_wait(&(th->_cond), &(th->_mutex));
            T task;
            th->pop(task);
            cout << pthread_self() << "获得任务:" << task.toTaskString() << endl;
            cout << "计算结果为:" << task() << endl;
            pthread_mutex_unlock(&(th->_mutex));
        }
        return nullptr;
    }

public:
    pthreadPool(int num = 3) : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; ++i)
        {
            _threads.push_back(new Thread());
        }
    }
    ~pthreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (int i = 0; i < _num; ++i)
        {
            delete _threads[i];
        }
    }
    void run()
    {
        for (int i = 0; i < _num; ++i)
        {
            _threads[i]->start(handlerTask, this);
        }
    }
    void push(const T &date)
    {
        pthread_mutex_lock(&_mutex);
        _tasks.push(date);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }
    static pthreadPool<T> *getInstance()
    {
        if (_tp == nullptr)
        {
            pthread_mutex_lock(&_sin);
            if (_tp == nullptr)
            {
                _tp = new pthreadPool(3);
            }
            pthread_mutex_unlock(&_sin);
        }
        return _tp;
    }
    pthreadPool(const pthreadPool<T> &tp) = delete;
    pthreadPool<T> operator=(pthreadPool<T>) = delete;

private:
    int _num;
    vector<Thread *> _threads;
    queue<T> _tasks;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static pthreadPool<T> *_tp;
    static pthread_mutex_t _sin;
};
template <class T>
pthreadPool<T> *pthreadPool<T>::_tp = nullptr;

template <class T>
pthread_mutex_t pthreadPool<T>::_sin = PTHREAD_MUTEX_INITIALIZER;
